using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Diagnostics;
using System.ComponentModel;

using phorm.database.core;

namespace phorm.model.fields
{
    /// <summary>
    /// Used to describe a column that relates to another record
    /// </summary>
    /// <typeparam name="T">A specific DatabaseRecord that is the relative to this ForeignKey column</typeparam>
    public class ForeignKey<T> : DatabaseColumn, IJoinableColumn
    {
        /// <summary>
        /// The relative DatabaseRecord
        /// </summary>
        public T relative;

        /// <summary>
        /// Constructor that builds the ForeignKey column into its model object.
        /// </summary>
        /// <param name="obj">The record to which this column belongs.</param>
        public ForeignKey(DatabaseRecord obj)
        {
            this._model   = obj;
            try
            {
                Type type    = typeof(T);
                Type current = Type.GetType(this._model.ToString());

                if (type.Name.ToString() != current.Name.ToString())
                {
                    this.relative   = (T) Activator.CreateInstance(type);

                    PrimaryKey pk   = this.relative.GetType().GetField("primary_key").GetValue(this.relative) as PrimaryKey;
                    this.field_type = pk.field_type;
                    this.length     = pk.length;

                    populateColumn();
                }
                else
                {
                    throw new Exception("Fatal: ForeignKey in "+current.Name.ToString()+" cannot point to itself");
                }
            }
            catch(Exception e)
            {
                Debug.Write("ForeignKey Exception: "+e.Message);
            }

        }

        /// <summary>
        /// Adds a record to this column's model object; saving it if necessary.
        /// </summary>
        /// <param name="obj">The record to be added</param>
        public void add(T obj)
        {
            this.relative = obj;
            DatabaseRecord record = obj as DatabaseRecord;
            if (record.primary_key.value == null)
                record.save();

            this.value = record.primary_key.value;
        }
    }
}
